// SPDX-FileCopyrightText: Adam Evyčędo
//
// SPDX-License-Identifier: AGPL-3.0-or-later

package traffic

import (
	"bufio"
	"encoding/csv"
	"fmt"
	"io"
	"net/http"
	"os"
	"path/filepath"
	"time"

	"golang.org/x/text/transform"
)

type RockHillMyRide struct {
	client http.Client
}

func (RockHillMyRide) getTimezone() *time.Location {
	l, _ := time.LoadLocation("America/New_York")
	return l
}

func (g RockHillMyRide) ConvertVehicles() ([]Vehicle, error) {
	return []Vehicle{}, nil
}

func (z RockHillMyRide) GetVersions(_ time.Time, timezone *time.Location) ([]Version, error) {
	version, err := MakeVersionTimezone("00000101_99991231", timezone)
	if err != nil {
		return nil, err
	}
	version.Link = "https://rapid.nationalrtap.org/GTFSFileManagement/UserUploadFiles/11718/myriderockhill-sc-us.zip"
	return []Version{version}, nil
}

func (RockHillMyRide) String() string {
	return "rockhill_myride"
}

func (RockHillMyRide) RealtimeFeeds() map[RealtimeFeedType]string {
	return map[RealtimeFeedType]string{}
}

func (RockHillMyRide) Transformer() transform.Transformer {
	return transform.Nop
}

func (RockHillMyRide) Name() string {
	return "Rock Hill, SC My Ride"
}

func (RockHillMyRide) Flags() FeedFlags {
	return FeedFlags{
		Headsign:     HeadsignTripHeadsing,
		StopIdFormat: "{{stop_code}}",
		StopName:     "{{stop_name}} [{{stop_code}}]",
		LineName:     "{{route_short_name}} {{route_long_name}}",
	}
}

func (RockHillMyRide) FeedPrepareZip(path string) error {
	// NOTE interpolate stop_times AND add timepoint
	stopTimesFile, err := os.Open(filepath.Join(path, "stop_times.txt"))
	if err != nil {
		return fmt.Errorf("while opening stop_times file: %w", err)
	}
	defer stopTimesFile.Close()
	stopTimes2File, err := os.OpenFile(filepath.Join(path, "stop_times2.txt"), os.O_RDWR|os.O_CREATE, 0644)
	if err != nil {
		return fmt.Errorf("while opening stop_times2 file: %w", err)
	}
	defer stopTimes2File.Close()
	r := csv.NewReader(bufio.NewReader(stopTimesFile))
	w := csv.NewWriter(stopTimes2File)
	header, err := r.Read()
	if err != nil {
		return fmt.Errorf("while reading stop_times header: %w", err)
	}
	fields := map[string]int{}
	for i, headerField := range header {
		fields[headerField] = i
	}
	header = append(header, "timepoint")
	err = w.Write(header)
	if err != nil {
		return fmt.Errorf("while writing stop_times header: %w", err)
	}

	lastTripID := ""
	lastKnownTime := 0
	collectedRecords := [][]string{}
	for {
		record, err := r.Read()
		if err == io.EOF {
			break
		}
		if err != nil {
			return fmt.Errorf("while reading a stop_times record: %w", err)
		}

		tripID := record[fields["trip_id"]]
		arrivalTime := record[fields["arrival_time"]]
		if tripID != lastTripID && arrivalTime == "" {
			return fmt.Errorf("no arrival time at the beginning of the trip ‘%s’", tripID)
		}

		if arrivalTime != "" {
			dT, err := parseDepartureTime(arrivalTime)
			if err != nil {
				return fmt.Errorf("incorrect end departure time %s: %w", arrivalTime, err)
			}
			if len(collectedRecords) > 0 {
				if tripID != lastTripID && lastTripID != "" {
					return fmt.Errorf("no arrival time at the end of the trip ‘%s’", lastTripID)
				}
				singleDuration := (dT - lastKnownTime) / (len(collectedRecords) + 1)
				for i, collectedRecord := range collectedRecords {
					collectedRecord[fields["arrival_time"]] = formatDepartureTime(lastKnownTime + ((i + 1) * singleDuration))
					collectedRecord = append(collectedRecord, "0")
					err = w.Write(collectedRecord)
					if err != nil {
						return fmt.Errorf("while writing a stop_times collected record %d: %w", i, err)
					}
				}
			}
			record = append(record, "1")
			err = w.Write(record)
			if err != nil {
				return fmt.Errorf("while writing a stop_times record: %w", err)
			}
			collectedRecords = [][]string{}
			lastKnownTime = dT
			lastTripID = tripID
		} else {
			collectedRecords = append(collectedRecords, record)
		}
	}
	w.Flush()
	err = os.Remove(filepath.Join(path, "stop_times.txt"))
	if err != nil {
		return fmt.Errorf("while removing stop_times: %w", err)
	}
	err = os.Rename(filepath.Join(path, "stop_times2.txt"), filepath.Join(path, "stop_times.txt"))
	if err != nil {
		return fmt.Errorf("while renaming stop_times: %w", err)
	}
	return nil
}

func (RockHillMyRide) QRInfo() (string, QRLocation, string) {
	return "", QRLocationNone, ""
}
